S3のバケットポリシーでハマったので、S3へのアクセスを許可するPrincipalの設定を整理する
S3はデータ置き場としてとても使えるやつで、他のアカウントと共有することも多いです。
複数AWSアカウントを使用していると、「1つのAWSアカウントのS3にデータを集約したい。」なんてニーズがでてきます。
S3のバケットポリシーのPrincipalを設定する際、アクセスができなくてハマったので本ブログはその備忘録です。
S3がリクエストを許可する方法
S3がバケットオペレーションのリクエストを許可する方法は、公式ドキュメントに記載されています。
内容が複雑なのでざっくり説明します。
たとえばIAMユーザーでS3にアクセスする状況を考えます。 IAMユーザーの親AWSアカウントがバケット所有者の場合、IAMユーザーのポリシーとバケットポリシーどちらかで明示的な許可を持っているとき、アクセスできます。
一方、IAMユーザーの親AWSアカウントがバケット所有者でない場合、IAMユーザーのポリシーとバケットポリシー両方で明示的な許可を持っているとき、アクセスできます。
大枠が理解できたところで、IAMポリシーとバケットポリシーの具体例を交えて、ハマった状況をご紹介します。
下準備
具体例を出すために、S3バケットとIAMユーザーを作成します。
S3バケットとIAMユーザーについては、先日のブログと同様の環境を使用します。作成手順については、こちらのブログを御覧ください。
別アカウントのS3バケットを利用する
別アカウントのS3バケットを利用する場合、IAMユーザーのポリシーとバケットポリシー、両方の許可を持っている必要があります。
バケットがあるAWSアカウントをアカウントA(アカウントID:111111111111)、 IAMユーザーがあるAWSアカウントをアカウントB(アカウントID:222222222222)とします。
ポリシーをこんな感じに設定すると、アクセスできます。
※便宜上、S3バケット名を ${S3_BUCKET_NAME}
に変更しています。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "222222222222" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}" } ] }
S3のバケットポリシーで特定のAWSアカウントに対してアクセス許可を与えたい場合、PrincipalにAWSアカウントのIDを設定することで、許可を付与するこができます。 詳細は公式ドキュメントを御覧ください。
※便宜上、S3バケット名を ${S3_BUCKET_NAME}
に変更しています。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}" } ] }
このようにバケットポリシーとIAMポリシー両方許可することで、別アカウントのS3バケットにアクセスできます。
$ export S3_BUCKET_NAME=<<BUCKET_NAME>> $ aws s3 ls s3://${S3_BUCKET_NAME} 2019-08-16 15:36:06 13 hello_world.html
どちらかのポリシーを許可していないと、アクセスは拒否されます。
$ export S3_BUCKET_NAME=<<BUCKET_NAME>> $ aws s3 ls s3://${S3_BUCKET_NAME} An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
同じアカウントのS3バケットを利用する(失敗パターン)
同じアカウントのS3バケットを利用する場合、IAMユーザーのポリシーとバケットポリシー、どちらかの許可をもっている必要があります。
ですので、IAMポリシーでそのバケットに対する操作が許可されていれば、バケットポリシーで許可されていなくてもS3にアクセスできます。
※便宜上、S3バケット名を ${S3_BUCKET_NAME}
に変更しています。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}" } ] }
$ export S3_BUCKET_NAME=<<BUCKET_NAME>> $ aws s3 ls s3://${S3_BUCKET_NAME} 2019-08-16 15:36:06 13 hello_world.html
同様に、バケットポリシーだけ許可の設定をしていればS3にアクセスできるだろうと思っていたのですが、これがうまくいかなくてハマりました。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "111111111111" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}" } ] }
$ export S3_BUCKET_NAME=<<BUCKET_NAME>> $ aws s3 ls s3://${S3_BUCKET_NAME} An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
同じアカウントのS3バケットを利用する(成功パターン)
PrincipalにIAMユーザーのArnを明示することで、バケットポリシーのみ許可した設定でアクセスが可能でした。
unauthorized-user
という名前で何も許可されていないIAMユーザーを作成します。
そのユーザーArnからのアクセスを許可するバケットポリシーを設定します。
※便宜上、S3バケット名を ${S3_BUCKET_NAME}
に変更しています。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:user/unauthorized-user" }, "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}" } ] }
このバケットポリシーを設定していれば、IAMポリシーでは許可がない unauthorized-user
からS3にアクセスできました。
$ export S3_BUCKET_NAME=<<BUCKET_NAME>> $ aws s3 ls s3://${S3_BUCKET_NAME} 2019-08-16 15:36:06 13 hello_world.html
まとめ
IAMポリシーとバケットポリシーの許可について表でまとめるとこんな感じです。
IAMユーザーとS3が同じアカウントか | IAMポリシー | バケットポリシー(ユーザーArn指定) | バケットポリシー(AWSアカウント指定) | 備考 |
---|---|---|---|---|
同じ | いずれか必要 | いずれか必要 | - | IAMポリシーまたはバケットポリシーのどちらかで許可されていればアクセス可能 |
異なる | 許可必須 | いずれか必要 | いずれか必要 | IAMポリシーとバケットポリシー両方の許可が必要。バケットポリシーはユーザーArnでもAWSアカウント指定でもOK |
挙動としてはそうなることが確認できましたが、どういう理屈でそうなるのかはよくわかりませんでした。 知っている方がいれば、こっそり教えてください。